using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Xml.Serialization;
using PHSRAG.Insight21.BusinessObjects;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;

namespace PHSRAG.Insight.Agreements.Arra
{
    /// <summary>
    /// Represents an ARRA PI questionnaire.
    /// </summary>
    [Serializable]
    public class PIQuestionnaire : SmartBusinessObject
    {
        #region Constants

        private const string ColNameArraAgreementID = "ArraAgreementID";
        private const string ColNameArraPIQuestionnaireID = "ArraPIQuestionnaireID";
        private const string ColNameChiefCode = "ChiefCode";
        private const string ColNameDepartment = "Department";
        private const string ColNameDepartmentAdmin = "DepartmentAdmin";
        private const string ColNameJobID = "ArraPIQuestionnaireJobID";
        private const string ColNameJobTitle = "JobTitle";
        private const string ColNameJobType = "ArraPIQuestionnaireJobType";
        private const string ColNameJobTypeID = "ArraPIQuestionnaireJobTypeID";
        private const string ColNameNarrative = "Narrative";
        private const string ColNameOrganization = "Institution";
        private const string ColNamePeopleSoftNumber = "FundNumber";
        private const string ColNamePercentEffort = "PercentEffort";
        private const string ColNamePIName = "PIName";
        private const string ColNamePIStateID = "ArraPIQuestionnaireEventID";
        private const string ColNameProjectTitle = "ShortTitle";
        private const string ColNameQuarterEndDtm = "QuarterEndDate";
        private const string ColNameQuarterlyActivitiesDescription = "QuarterlyActivities";
        private const string ColNameResearchMgmtAdmin = "ResearchMgmtAdmin";
        private const string ColNameSponsor = "SponsorName";
        private const string ColNameSponsorAwardNumber = "SponsorNumber";
        public const string PIQuestionnaireCacheKey = "PIQuestionnaire_32b5ca66-1dfa-4c1e-bd14-0cdf90f064e2";
        private const string SprocNameGetArraPIQuestionnaire = "GetArraPIQuestionnaire";
        private const string SprocNameGetArraPIQuestionnaireJobs = "GetArraPIQuestionnaireJobs";
        private const string SprocNameGetArraPIQuestionnaireJobTypes = "GetArraPIQuestionnaireJobTypes";
        private const string SprocNameSaveArraPIQuestionnaire = "SaveArraPIQuestionnaire";

        #endregion

        #region Private Variables

        private readonly IDictionary<int, string> jobTypes;
        private int agreementID;
        private string chiefCode;
        private string department;
        private string departmentAdmin;
        private List<Job> jobs;
        private string narrative;
        private string organization;
        private string peopleSoftNumber;
        private int personID;
        private string piName;
        private string projectTitle;
        private DateTime quarterEndDtm;
        private string quarterlyActivitiesDescription;
        private string researchMgmtAdmin;
        private string sponsor;
        private string sponsorAwardNumber;
        private PIQuestionnaireState state;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PIQuestionnaire"/> class.
        /// </summary>
        /// <param name="cachePolicy">cache poliCy determines where the object will be cached</param>
        public PIQuestionnaire(ICachePolicy cachePolicy)
            : base(cachePolicy)
        {
            jobs = new List<Job>();
            jobTypes = new Dictionary<int, string>();
        }

        #endregion

        #region Overrides of SmartBusinessObject

        /// <summary>
        /// Cache Key uniquely identifies this object in the cache.
        /// </summary>
        public override string CacheKey()
        {
            return PIQuestionnaireCacheKey;
        }

        /// <summary>
        /// Loads the object based on some parameters
        /// </summary>
        /// <param name="connectionString">Database connection string</param>
        /// <param name="args">
        /// Collection of parameters. 
        /// 1st argument (index 0) - ID of either PI Questionaire or ARRA Agreement.
        /// 2nd argument (index 1) - indicator of whether the ID (1st argument) is of PI Questionnaire or ARRA Agreement. 
        /// If 2nd argument == true, then 1st argument is ID of PI questionnaire, otherwise - ID of ARRA Agreement.
        /// </param>
        public override void Load(string connectionString, params object[] args)
        {
            int id = (int) args[0];
            bool isPIQuestionnaireID = (bool) args[1];

            LoadPIQuestionnaire(id, isPIQuestionnaireID, connectionString);
            LoadPIQuestionnaireJobTypes(connectionString);
            LoadPIQuestionnaireJobs(id, isPIQuestionnaireID, connectionString);
        }

        /// <summary>
        /// Save only the business object's data members (only those members which contribute to the
        /// dirty state). This is called in the public Save method, if the object is determined to be
        /// dirty and need saving.
        /// </summary>
        /// <param name="sqlTransaction">transaction passed in to do the saving on.</param>
        protected override void SaveObject(SqlTransaction sqlTransaction)
        {
            SavePIQuestionnaireWithJobs(sqlTransaction);
        }

        /// <summary>
        /// Deletes the object requested, and potentially any of its contained objects, if 
        /// the delete of those are implemented and called.
        /// </summary>
        /// <param name="sqlTransaction">transaction passed in to do the saving on.</param>
        protected override void DeleteObject(SqlTransaction sqlTransaction)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Cache this instance using the prevalent cache policy.
        /// </summary>
        public override void Cache()
        {
            CachePolicy.Cache(CacheKey(), this);
        }

        /// <summary>
        /// Remove this instance from the cache using the prevalent cache policy.
        /// </summary>
        public override void UnCache()
        {
            CachePolicy.UnCache(CacheKey());
        }

        #endregion

        #region Public Properties

        public int AgreementID
        {
            get { return agreementID; }
            set { agreementID = value; }
        }

        public string PIName
        {
            get { return piName; }
            set { piName = value; }
        }

        public string ProjectTitle
        {
            get { return projectTitle; }
            set { projectTitle = value; }
        }

        public string PeopleSoftNumber
        {
            get { return peopleSoftNumber; }
            set { peopleSoftNumber = value; }
        }

        public string ChiefCode
        {
            get { return chiefCode; }
            set { chiefCode = value; }
        }

        public string Organization
        {
            get { return organization; }
            set { organization = value; }
        }

        public string Department
        {
            get { return department; }
            set { department = value; }
        }

        public string Sponsor
        {
            get { return sponsor; }
            set { sponsor = value; }
        }

        public string SponsorAwardNumber
        {
            get { return sponsorAwardNumber; }
            set { sponsorAwardNumber = value; }
        }

        public DateTime QuarterEndDtm
        {
            get { return quarterEndDtm; }
            set { quarterEndDtm = value; }
        }

        public string DepartmentAdmin
        {
            get { return departmentAdmin; }
            set { departmentAdmin = value; }
        }

        public string ResearchMgmtAdmin
        {
            get { return researchMgmtAdmin; }
            set { researchMgmtAdmin = value; }
        }

        public List<Job> Jobs
        {
            get { return jobs; }
            set { jobs = value; }
        }

        public string Narrative
        {
            get { return narrative; }
            set { narrative = value; }
        }

        public string QuarterlyActivitiesDescription
        {
            get { return quarterlyActivitiesDescription; }
            set { quarterlyActivitiesDescription = value; }
        }

        public PIQuestionnaireState State
        {
            get { return state; }
            set { state = value; }
        }

        public IDictionary<int, string> JobTypes
        {
            get { return jobTypes; }
        }

        public int PersonID
        {
            get { return personID; }
            set { personID = value; }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the PI questionnaire.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="isPIQuestionnaireID">if set to <c>true</c> then the ID is of PI questionnaire.</param>
        /// <param name="connectionString">The connection string.</param>
        private void LoadPIQuestionnaire(int id, bool isPIQuestionnaireID, string connectionString)
        {
            SqlParameter[] sqlParams = DataAccess.BuildSqlParameterArray(
                "@id", SqlDbType.Int, id,
                "@isPIQuestionnaireID", SqlDbType.Bit, isPIQuestionnaireID);

            SqlDataReader sqlReader = DataAccess.ExecuteReader(connectionString, SprocNameGetArraPIQuestionnaire, sqlParams);

            if (sqlReader.HasRows)
            {
                sqlReader.Read();

                Id = sqlReader.GetInt32(sqlReader.GetOrdinal(ColNameArraPIQuestionnaireID));
                AgreementID = sqlReader.GetInt32(sqlReader.GetOrdinal(ColNameArraAgreementID));
                PIName = sqlReader[ColNamePIName].ToString();
                ProjectTitle = sqlReader[ColNameProjectTitle].ToString();
                PeopleSoftNumber = sqlReader[ColNamePeopleSoftNumber].ToString();
                ChiefCode = sqlReader[ColNameChiefCode].ToString();
                Organization = sqlReader[ColNameOrganization].ToString();
                Department = sqlReader[ColNameDepartment].ToString();
                Sponsor = sqlReader[ColNameSponsor].ToString();
                SponsorAwardNumber = sqlReader[ColNameSponsorAwardNumber].ToString();
                QuarterEndDtm = sqlReader.GetDateTime(sqlReader.GetOrdinal(ColNameQuarterEndDtm));
                DepartmentAdmin = sqlReader[ColNameDepartmentAdmin].ToString();
                ResearchMgmtAdmin = sqlReader[ColNameResearchMgmtAdmin].ToString();
                Narrative = sqlReader[ColNameNarrative].ToString();
                QuarterlyActivitiesDescription = sqlReader[ColNameQuarterlyActivitiesDescription].ToString();
                State = (PIQuestionnaireState) sqlReader.GetInt32(sqlReader.GetOrdinal(ColNamePIStateID));
            }

            sqlReader.Close();
        }

        /// <summary>
        /// Loads the PI questionnaire jobs.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="isPIQuestionnaireID">if set to <c>true</c> then the ID is of PI questionnaire.</param>
        /// <param name="connectionString">The connection string.</param>
        private void LoadPIQuestionnaireJobs(int id, bool isPIQuestionnaireID, string connectionString)
        {
            SqlParameter[] sqlParams = DataAccess.BuildSqlParameterArray(
                "@id", SqlDbType.Int, id,
                "@isPIQuestionnaireID", SqlDbType.Bit, isPIQuestionnaireID);

            SqlDataReader sqlReader = DataAccess.ExecuteReader(connectionString, SprocNameGetArraPIQuestionnaireJobs, sqlParams);

            while (sqlReader.Read())
            {
                Job job = new Job();
                job.ID = sqlReader.GetInt32(sqlReader.GetOrdinal(ColNameJobID));
                job.TypeID = sqlReader.GetInt32(sqlReader.GetOrdinal(ColNameJobTypeID));
                job.Type = sqlReader[ColNameJobType].ToString();
                job.Title = sqlReader[ColNameJobTitle].ToString();
                job.PercentEffort = (int) sqlReader.GetDecimal(sqlReader.GetOrdinal(ColNamePercentEffort));
                Jobs.Add(job);
            }

            sqlReader.Close();
        }

        /// <summary>
        /// Loads the job types available for ARRA PI questionnaire jobs.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        private void LoadPIQuestionnaireJobTypes(string connectionString)
        {
            SqlDataReader sqlReader = DataAccess.ExecuteReader(connectionString, SprocNameGetArraPIQuestionnaireJobTypes);

            while (sqlReader.Read())
            {
                JobTypes.Add(sqlReader.GetInt32(sqlReader.GetOrdinal(ColNameJobTypeID)), sqlReader[ColNameJobType].ToString());
            }

            sqlReader.Close();
        }

        /// <summary>
        /// Saves ARRA PI questionnaire with it's jobs to DB.
        /// </summary>
        /// <param name="sqlTransaction">SQL transaction.</param>
        private void SavePIQuestionnaireWithJobs(SqlTransaction sqlTransaction)
        {
            StringWriter sw = new StringWriter();
            new XmlSerializer(Jobs.GetType(), new XmlRootAttribute("Jobs")).Serialize(sw, Jobs);

            SqlParameter[] sqlParams = DataAccess.BuildSqlParameterArray(
                "@arraAgreementID", SqlDbType.Int, AgreementID,
                "@narrative", SqlDbType.VarChar, Narrative,
                "@quarterlyActivities", SqlDbType.VarChar, QuarterlyActivitiesDescription,
                "@personID", SqlDbType.Int, PersonID,
                "@xmlJobs", SqlDbType.Xml, sw.ToString(),
                "@state", SqlDbType.Int, (int) State);

            if (Id != 0)
            {
                DataAccess.AppendToSqlParameterArray(ref sqlParams, "@arraPIQuestionnaireID", SqlDbType.Int, Id);
            }

            DataAccess.ExecuteNonQuery(sqlTransaction.Connection, sqlTransaction, SprocNameSaveArraPIQuestionnaire, sqlParams);
        }

        #endregion
    }
}